using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Tracing;
using System.Threading;
using System.Threading.Tasks;
using Windows.Storage;

namespace NewsReader.Log
{
    /// <summary>
    /// This is an advanced useage, where you want to intercept the logging messages and devert them somewhere
    /// besides ETW.
    /// </summary>
    public sealed class StorageFileEventListener : EventListener
    {
        /// <summary>
        /// Storage file to be used to write logs
        /// </summary>
        private StorageFile _storageFile = null;

        /// <summary>
        /// Name of the current event listener
        /// </summary>
        private string _name;

        /// <summary>
        /// The format to be used by logging.
        /// </summary>
        private string _logFormat = "{0:yyyy-MM-dd HH\\:mm\\:ss\\:ffff}\tType: {1}\tId: {2}\tMessage: '{3}'";

        private SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1);

        public StorageFileEventListener(string name)
        {
            _name = name;
            Debug.WriteLine("StorageFileEventListener for {0} has name {1}", GetHashCode(), name);
            AssignLocalFile();
        }

        private
#if DEBUG
            async 
#endif   
            void AssignLocalFile()
        {
#if DEBUG
            _storageFile = await ApplicationData.Current.LocalFolder.CreateFileAsync(_name.Replace(" ", "_") + ".log",
                                                                                      CreationCollisionOption.OpenIfExists);
#endif
        }

        private async Task WriteToFile(IEnumerable<string> lines)
        {
            await _semaphoreSlim.WaitAsync();

            await Task.Run(async () =>
                                     {
                                         try
                                         {
                                             await FileIO.AppendLinesAsync(_storageFile, lines);
                                         }
                                         catch (Exception)
                                         {
                                             // TODO:
                                         }
                                         finally
                                         {
                                             _semaphoreSlim.Release();
                                         }
                                     });
        }

        protected override void OnEventWritten(EventWrittenEventArgs eventData)
        {
            if (_storageFile == null) return;

            var lines = new List<string>();

            var newFormatedLine = string.Format(_logFormat, DateTime.Now, eventData.Level, eventData.EventId, eventData.Payload[0]);
            
            Debug.WriteLine(newFormatedLine);

            lines.Add(newFormatedLine);

            WriteToFile(lines).ContinueWith(t =>
                {
                    if (t.IsFaulted)
                    {
                        Logger.Log.ErrorFormat("WriteToFile failed. Exception {0}", t.Exception);
                    }
                });
        }

        protected override void OnEventSourceCreated(EventSource eventSource)
        {
            Debug.WriteLine("OnEventSourceCreated for Listener {0} - {1} got eventSource {2}", GetHashCode(), _name, eventSource.Name);
        }
    }
}